﻿import base = require('../base');
import aop = require('../aop');

/**
 * 代码：文件找不到,Not Found
 */
export const code_FileNotFound = 404;
/**
 * 代码：成功
 */
export const code_Success = 200;
/**
 * 请求类型
 */
export type reuqestType = "GET" | "POST";
/**
 * 创建JsonAjax设置
 * @param url url
 * @param serviceName 服务名称
 * @param functionName 方法名称
 * @param args 参数
 */
function createJsonAjaxSettings(url: string, serviceName: string, functionName: string, args: any[]): JQueryAjaxSettings {
    let settings: JQueryAjaxSettings = {};
    let header: base.remoteHeader;
    if (base.currentUser) {
        header = {
            userID: base.currentUser.name,
            password: base.currentUser.password
        }
    }
    settings.url = url;
    settings.type = "POST";
    settings.dataType = "json";
    /** 发送信息前设置类型信息 */
    settings.data = JSON.stringify({
        serviceName: serviceName,
        functionName: functionName,
        header: header,
        args: aop.addonSerialize(args)
    });
    return settings;
}

/**
 * 同步json调用
 * @param url 服务地址
 * @param serviceName 服务名称
 * @param functionName 方法名称
 * @param args 参数
 */
export function jsonCall(url: string, serviceName: string, functionName: string, args?: any[]): any {
    let settings: JQueryAjaxSettings = createJsonAjaxSettings(url, serviceName, functionName, args);
    let returnValue: any;
    settings.async = false;
    settings.crossDomain = true;
    settings.success = (response) => {
        returnValue = response;
        if (returnValue) {
            // 返回值处理前要获取类型原型
            aop.fetchAddonProtoType(returnValue);
        }
    };
    settings.error = (xhr, status, err) => {
        throw new Error(JSON.stringify(xhr));
    };
    $.ajax(settings);
    return returnValue.d;
}

/**
 * 异步json调用
 * @param url 服务地址
 * @param serviceName 服务名称
 * @param functionName 方法名称
 * @param args 参数
 */
export function asyncJsonCall(url: string
    , serviceName: string
    , functionName: string
    , args?: any[]
    , success?: (result: any) => void
    , error?: (err: Error) => void) {
    let settings: JQueryAjaxSettings = createJsonAjaxSettings(url, serviceName, functionName, args);
    settings.async = true;
    settings.crossDomain = true;
    settings.success = (response) => {
        let returnValue = response;
        if (returnValue) {
            // 返回值处理前要获取类型原型
            aop.fetchAddonProtoType(returnValue);
        }
        if (success) {
            // 处理返回值
            success(returnValue);
        }
    };
    settings.error = (xhr, status, err) => {
        if (error) {
            error(new Error(JSON.stringify(xhr)));
        }
    };
    $.ajax(settings);
}


/**
 * 脚本库列表
 */
let scriptLibs: string[] = [];
/**
 * 动态加载JavaScript 库
 * @param url 待加载库的url
 * @param forceToDuplicateLoad 强制重新加载
 * @remark url必须是../开头的相对地址
 */
export function loadScript(url: string, forceToDuplicateLoad: boolean = false) {
    /** 非强行加载 */
    if (!forceToDuplicateLoad && scriptLibs[url]) {
        return;
    }

    $.ajax({
        url: url,
        dataType: "text",
        async: false,
        success: (scr, status, xhr) => {
            // Execut JavaScript
            eval(scr);
            scriptLibs.push(url);
        },
        error: (xhr, status, err) => {
            // The JavaScript File not Found
            if (xhr.status == code_FileNotFound)
                return;
            // Other Error Status
            else
                throw new Error(`脚本加载异常, 状态码: ${xhr.status} , 错误描述 : ${err}`);
        }
    });
}

/**
 * 动态加载JavaScript库集
 * @param scripts
 */
export function loadScripts(scripts: string[]) {
    for (var script of scripts) {
        loadScript(script);
    }
}

/**
 * 动态加载 css 文件
 * @param url 待加载css文件的url
 * @param type 
 * @param rel
 */
export function loadStyle(url: string) {
    loadLink(url, "text/css", "stylesheet");
}

/**
 * 动态加载 css 文件集
 * @param urls css文件集url
 */
export function loadStyles(urls: string[]) {
    for (var url of urls) {
        loadStyle(url);
    }
}

/**
 * 动态加载Json
 * @param url 待加载Json的url
 * @remark url必须是../开头的相对地址
 */
export function loadJson(url: string): any {
    let jsonObject: any;

    $.ajax({
        url: url,
        dataType: "json",
        async: false,
        success: (scr, status, xhr) => {
            jsonObject = scr;
        },
        error: (xhr, status, err) => {
            throw new Error(`Json加载异常, 状态码: ${xhr.status} , 错误描述 : ${err}`);
        }
    });

    return jsonObject;
}

/**
 * 动态加载 link 标签
 * @param url 待加载文件的url
 * @param type 文件类型
 * @param rel 
 */
export function loadLink(url: string, type: string, rel: string) {
    var link = document.createElement("link");
    link.type = type;
    link.rel = rel;
    link.href = url;
    document.getElementsByTagName("head")[0].appendChild(link);
}


/**
 * 加载模板
 * @param url 地址
 * @param callback 回调函数
 */
export function getTemplate(url: string, callback: Function) {
    $.get(url, (data, status, xhr) => {
        ;
        // 成功
        if (xhr.status == code_Success) {
            callback.apply(this, [data]);
        }
        else if (xhr.status == code_FileNotFound) {
            throw new Error(`文件不存在，地址：${url}`);
        } else {
            throw new Error(`获取文件异常【状态码：${xhr.status}，地址：${url}】`);
        }
    },"text");
}


const moduleName = "kf.client";
/**
 * 远程工厂: 通过JSON实现远程调用
 */
@aop.addon("远程工厂",
    "通过JSON实现远程调用",
    moduleName)
export class remoteFactory extends aop.baseObject implements aop.factory {
    constructor(public proxyTypeName: string, public url: string, public serviceName: string) {
        super();
    }
    getValue?(): any {
        let typeConstructor = aop.getAddonTypeByFullName(this.proxyTypeName);
        return base.proxy.createTransparentProxy(typeConstructor, (methodName: any, args: any) => {
            return jsonCall(this.url, this.serviceName, methodName, args);
        });
    }
}
